package com.atguigu.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.client.CartFeignClient;
import com.atguigu.client.ProductFeignClient;
import com.atguigu.constant.MqConst;
import com.atguigu.entity.OrderDetail;
import com.atguigu.entity.OrderInfo;
import com.atguigu.enums.OrderStatus;
import com.atguigu.enums.ProcessStatus;
import com.atguigu.executor.MyExecutor;
import com.atguigu.mapper.OrderInfoMapper;
import com.atguigu.service.OrderDetailService;
import com.atguigu.service.OrderInfoService;
import com.atguigu.util.HttpClientUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * <p>
 * 订单表 订单表 服务实现类
 * </p>
 *
 * @author GuoJH
 * @since 2021-09-07
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrderDetailService orderDetailService;
    @Resource
    private ProductFeignClient productFeignClient;
    @Autowired
    private CartFeignClient cartFeignClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Value("${cancel.order.delay}")
    private Integer CancelOrderDelay;
    //设置交易编号
    @Override
    public String getTradeNo(String userId) {
        String tradeNo = UUID.randomUUID().toString();
        //定义一个key  放入redis中一份
        String tradeNoKey = "user:"+userId+":tradeNo";
        redisTemplate.opsForValue().set(tradeNoKey,tradeNo);
        return tradeNo;
    }

    //对比交易编号防止没有刷新页面重复提交问题
    @Override
    public boolean checkTradeNo(String tradeNo, String userId) {
        String tradeNoKey = "user:"+userId+":tradeNo";
        String redisTradeNo = (String)redisTemplate.opsForValue().get(tradeNoKey);
        return tradeNo.equals(redisTradeNo);
    }

    //验证完成之后 删除掉交易编号(让每次刷新页面 都生成不一样的交易编号)
    @Override
    public void deleteTradeNo(String userId) {
        String tradeNoKey = "user:"+userId+":tradeNo";
        redisTemplate.delete(tradeNoKey);
    }
    //保存订单信息
    @Override
    public Long saveOrderInfoAndDetail(OrderInfo orderInfo) {
        //赋值给订单信息中没有的
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());//订单状态
        //设置订单交易编号
        String outTradeNo = "SHOP"+System.currentTimeMillis()+""+new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);
        orderInfo.setTradeBody("购物商品的信息");//订单的描述
        orderInfo.setCreateTime(new Date());
        Calendar instance = Calendar.getInstance();//获取当前的时间
        instance.add(Calendar.DATE,1);//进行+1
        orderInfo.setExpireTime(instance.getTime());//订单支付过期时间
        orderInfo.setProcessStatus(OrderStatus.UNPAID.name());//订单的进程
        baseMapper.insert(orderInfo);

        //保存商品清单信息
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (!CollectionUtils.isEmpty(orderDetailList)){
            for (OrderDetail orderDetail : orderDetailList) {
                orderDetail.setOrderId(orderInfo.getId());
            }
            orderDetailService.saveBatch(orderDetailList);
        }
        //设置定时支付时间 超过后取消订单
        rabbitTemplate.convertAndSend(
                MqConst.CANCEL_ORDER_EXCHANGE,
                MqConst.CANCEL_ORDER_ROUTE_KEY,
                orderInfo.getId(),
                correlationData->{//设置其他参数 订单的过期时间
                    correlationData.getMessageProperties().setDelay(CancelOrderDelay);
                    return correlationData;
                });

        return orderInfo.getId();
    }
    //验证是否还有库存  及下单前价格的变化
    //访问http://localhost:8100/hasStock?skuId=24&num=99  0:无库存  1:有库存
    @Override
    public List<String> checkStockAndPrice(OrderInfo orderInfo, String userId) {
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<String> retValList = new ArrayList<>();
        List<CompletableFuture> futureArrayList = new ArrayList<>();//统一返回异步
        if (!CollectionUtils.isEmpty(orderDetailList)){
            for (OrderDetail orderDetail : orderDetailList) {
                Long skuId = orderDetail.getSkuId();
                String skuNum = orderDetail.getSkuNum();

                //方式二  采用异步编排
                CompletableFuture<Void> completableStockFuture = CompletableFuture.runAsync(() -> {
                    String num = HttpClientUtil.doGet("http://localhost:8100/hasStock?skuId=" + skuId + "&num=" + skuNum);
                    if (num.equals("0")) {
                        retValList.add(orderDetail.getSkuName() + "库存余量不足!");
                    }
                }, MyExecutor.getInstance());
                CompletableFuture<Void> completablePriceFuture = CompletableFuture.runAsync(() -> {
                    BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
                    BigDecimal orderPrice = orderDetail.getOrderPrice();
                    if (skuPrice.compareTo(orderPrice) != 0) {
                        retValList.add(orderDetail.getSkuName() + "价格有变动,请重新刷新!");
                        //并将价格更新到redis中
                        cartFeignClient.queryCartInfoFromDbToRedis(userId);
                    }
                }, MyExecutor.getInstance());

                futureArrayList.add(completableStockFuture);
                futureArrayList.add(completablePriceFuture);
                /* //方式一
                //用HTTPClientUtil 发起请求 返回0:无库存  1:有库存
                String num = HttpClientUtil.doGet("http://localhost:8100/hasStock?skuId=" + skuId + "&num=" + skuNum);
                if (num.equals("0")){
                    retValList.add(orderDetail.getSkuName()+"库存余量不足!");
                }
                //验证实时价格
                BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
                BigDecimal orderPrice = orderDetail.getOrderPrice();
                if (skuPrice.compareTo(orderPrice) != 0){
                    retValList.add(orderDetail.getSkuName()+"价格有变动,请重新刷新!");
                    //并将价格更新到redis中
                    cartFeignClient.queryCartInfoFromDbToRedis(userId);
                }
                */
            }
        }
        //返回中需要传入一个数组 所以将集合转换为一个数组
        CompletableFuture[] completableFutures = new CompletableFuture[futureArrayList.size()];
        //所有的异步执行完之后在统一返回
        CompletableFuture.allOf(futureArrayList.toArray(completableFutures)).join();
        return retValList;
    }
    //修改订单的状态为关闭
    @Override
    public void updateOrderStatus(OrderInfo orderInfo, ProcessStatus processStatus) {
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());
        baseMapper.updateById(orderInfo);
    }
    //根据订单id获取订单的信息
    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = baseMapper.selectById(orderId);
        QueryWrapper<OrderDetail> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id",orderId);
        List<OrderDetail> orderDetailList = orderDetailService.list(wrapper);
        orderInfo.setOrderDetailList(orderDetailList);
        return orderInfo;
    }
    //利用mq发送消息给库存系统 减库存
    @Override
    public void sendMsgToWareManage(OrderInfo orderInfo) {
        //将订单状态更改为已通知仓库
        updateOrderStatus(orderInfo,ProcessStatus.NOTIFIED_WARE);
        Map<String, Object> paramMap = returnWareMap(orderInfo);

        String paramMapString = JSON.toJSONString(paramMap);
        rabbitTemplate.convertAndSend(MqConst.DECREASE_STOCK_EXCHANGE,MqConst.DECREASE_STOCK_ROUTE_KEY,paramMapString);
    }

    private Map<String, Object> returnWareMap(OrderInfo orderInfo) {
        //封装传递给库存系统的信息
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("orderId",orderInfo.getId());
        paramMap.put("consignee",orderInfo.getConsignee());
        paramMap.put("consigneeTel",orderInfo.getConsigneeTel());
        paramMap.put("orderComment",orderInfo.getOrderComment());
        paramMap.put("orderBody",orderInfo.getTradeBody());
        paramMap.put("deliveryAddress",orderInfo.getDeliveryAddress());
        paramMap.put("paymentWay",2);
        //减完库存后订单拆单使用
        paramMap.put("wareId",orderInfo.getWareHouseId());
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<Map<String, Object>> mapArrayList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderDetailList)){
            for (OrderDetail orderDetail : orderDetailList) {
                Map<String, Object> map = new HashMap<>();
                map.put("skuId",orderDetail.getSkuId());
                map.put("skuNum",orderDetail.getSkuNum());
                map.put("skuName",orderDetail.getSkuName());

                mapArrayList.add(map);
            }
        }
        paramMap.put("details",mapArrayList);
        return paramMap;
    }

    //拆单 因为商家不同 仓库不同 商品不同
    @Override
    public String splitOrder(Long orderId, String wareHouseIdSkuIdMap) {
        //通过订单id获取订单的信息  原始订单(未拆分)
        OrderInfo orderInfo = getOrderInfo(orderId);
        //拆分的子订单信息
        OrderInfo childOrderInfo = new OrderInfo();
        List<Map> mapList = new ArrayList<>();
        //将传过来的wareHouseIdSkuIdMap(仓库id和商品skuId的对应关系)转为list集合
        List<Map> wareHouseIdSkuIdMapList = JSON.parseArray(wareHouseIdSkuIdMap, Map.class);
        for (Map wareHouseIdSkuId : wareHouseIdSkuIdMapList) {
            //获取对应的仓库id
            String wareId = (String)wareHouseIdSkuId.get("wareHouseId");
            //获取对应的商品skuId
            List<String> skuIdList = (List<String>)wareHouseIdSkuId.get("skuIdList");

            //为子订单赋值  利用BeanUtils copy
            BeanUtils.copyProperties(orderInfo,childOrderInfo);
            childOrderInfo.setWareHouseId(wareId);//设置子订单对应的仓库id
            childOrderInfo.setParentOrderId(orderId);//设置对应的是哪个原始订单
            childOrderInfo.setId(null);//子订单的id不用设置 因为自增

            //获取原始订单的详情信息
            List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
            //创建子订单对应的详情信息
            ArrayList<OrderDetail> childOrderDetailList = new ArrayList<>();
            BigDecimal totalMoney = new BigDecimal(0);
            for (OrderDetail orderDetail : orderDetailList) {
                //迭代skuIdList  判断这个skuId跟原始订单详情中的skuId相互匹配
                for (String skuId : skuIdList) {
                    if (Long.parseLong(skuId) == orderDetail.getSkuId()){
                        childOrderDetailList.add(orderDetail);
                        totalMoney = totalMoney.add(orderDetail.getOrderPrice().multiply(new BigDecimal(orderDetail.getSkuNum())));
                    }
                }
            }
            //将子订单详情信息放入到子订单信息中
            childOrderInfo.setOrderDetailList(childOrderDetailList);
            childOrderInfo.setTotalMoney(totalMoney);
            //保存子订单
            saveOrderInfoAndDetail(childOrderInfo);
            //返回给库存系统数据
            Map<String, Object> returnWareMap = returnWareMap(childOrderInfo);
            mapList.add(returnWareMap);
        }
        //修改原始订单的状态
        updateOrderStatus(orderInfo,ProcessStatus.SPLIT);
        //将数据转为jsonString
        String jsonString = JSON.toJSONString(mapList);
        return jsonString;
    }
}
